package pl.gigiel.jme.behaviour.boidbody;

import pl.gigiel.behaviour.IBoid;
import pl.gigiel.behaviour.IBoidFeatures;
import pl.gigiel.behaviour.exception.BehaviourException;
import pl.gigiel.jme.behaviour.IBoidBody;

import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.scene.shape.Pyramid;
import com.jme.scene.state.MaterialState;
import com.jme.system.DisplaySystem;

public class SimpleBoidBody extends Node implements IBoidBody {
	private static final long serialVersionUID = 1L;
	private Node rootNode;
	private IBoid boid;

	public IBoid getBoid() {
		return boid;
	}

	public SimpleBoidBody(Node rootNode, IBoid boid) {
		super(boid.getFeatures().getId());
		this.rootNode = rootNode;
		this.boid = boid;
	}

	@Override
	public void init() throws BehaviourException {
		initAppearance();
		initController();
	}

	protected void process(float elapsed) {
		try {
			boid.prepare(elapsed);
			boid.perform();
			IBoidFeatures features = boid.getFeatures();
			Vector3f position = new Vector3f(features.getPosition());
			Vector3f direction = new Vector3f(features.getDirection());
			setLocalTranslation(position);
			rotateUpTo(direction);
		} catch (BehaviourException e) {
			// TODO logging, serving; no throws because of using in anonymous
			// Controller
			e.printStackTrace();
		}
	}

	protected void initAppearance() {
		MaterialState material = DisplaySystem.getDisplaySystem().getRenderer().createMaterialState();
		IBoidFeatures features = boid.getFeatures();
		material.setDiffuse(features.getColor());
		TriMesh shape = getTriMesh();
		shape.setRenderState(material);
		shape.updateRenderState();
		attachChild(shape);
		rootNode.attachChild(this);
	}

	protected TriMesh getTriMesh() {
		IBoidFeatures features = boid.getFeatures();
		Vector3f size = features.getSize();
		TriMesh triMesh = new Pyramid(Pyramid.class.getName(), size.getX(), size.getY());
		return triMesh;
	}

	protected void initController() {
		addController(new Controller() {
			private static final long serialVersionUID = 1L;

			public void update(float elapsed) {
				process(elapsed);
			}
		});
	}

	/*
	 * because of problem
	 */
	public void rotateUpTo(Vector3f newUp) {
		if (newUp.x == 0 && newUp.y == 0 && newUp.z == 0) {
			return;
		}
		if (newUp.x == 0 && newUp.z == 0) {
			newUp.x = 0.00001f;
		}
		super.rotateUpTo(newUp.normalize());
	}
}
